package serie09;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Polygon;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JComponent;

public class GraphicSpeedometer extends JComponent {
	
	// ATTRIBUTS
	
	private static final long serialVersionUID = 1L;
	
	private static final int
    // marge horizontale interne de part et d'autre du composant
    MARGIN       = 40,
    // �paisseur de la ligne horizontale gradu�e
    THICK        =  3,
    // demi-hauteur d'une graduation
    MARK         =  5,
    // largeur de la base du triangle pour la t�te de la fl�che
    ARROW_BASE   = 20,
    // �paisseur du corps de la fl�che
    ARROW_THICK  =  4,
    // hauteur du corps de la fl�che
    ARROW_HEIGHT = 20,
    // hauteur pr�f�r�e d'un GraphicSpeedometer
    PREFERRED_HEIGHT = 3 * (3 * MARK + ARROW_BASE / 2 + ARROW_HEIGHT);
	// facteur d'�chelle pour l'espacement entre deux graduations
	private static final double ASPECT_RATIO = 1.25;
	// couleurs gris�es utilis�es lorsque le moteur est �teint
	private static final Color
    	BLUE        = Color.BLUE,
    	RED         = Color.RED,
    	GRAYED_BLUE = new Color(0, 0, 255, 50),
    	GRAYED_RED  = new Color(255, 0, 0, 50);
	// les vitesses affich�es sont celles, entre 0 et model.getMaxSpeed(),
	//  qui sont les multiples de STEP
	private static final int STEP = 10;
	
	private static final int MAX = 100;
	
	// Y représente l'ordonnée du sommet de la flèche
	private static final int Y = 60;
	
	// X représente l'ordonnée de la barre horizontale
	private static final int X = 50;
	
	// le modèle
	private SpeedometerModel model;

	// CONSTRUCTEURS
	
	public GraphicSpeedometer() {
		model = new StdSpeedometerModel(10, MAX);
		this.setPreferredSize(new Dimension(
				(int) (2 * MARGIN 
						+ ASPECT_RATIO * ARROW_BASE * model.getMaxSpeed() / STEP
				), 
				PREFERRED_HEIGHT)
		);
		createView();
	}
	
	// REQUETES
	
	/**
	 * Retourne le modèle associé au graphique.
	 */
	public SpeedometerModel getModel() {
		return model;
	}
	
	// COMMANDES
	
	public void paintComponent(Graphics g) {
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, this.getWidth(), this.getHeight());
		if (model.isOn()) {
			g.setColor(BLUE);
		} else {
			g.setColor(GRAYED_BLUE);
		}
		int larg = this.getWidth();
		g.fillRect(MARGIN, X - THICK / 2, larg - 2 * MARGIN, THICK);
		int nbG = (int) (model.getMaxSpeed() / STEP);
		for (int i = 0; i <= nbG; i++) {
			int x = (int) (MARGIN 
					+ i * ((larg - 2 * MARGIN) / model.getMaxSpeed() * STEP));
			g.drawLine(x, X - MARK, x, X + MARK);
			FontMetrics fm = g.getFontMetrics();
			String s = ((Integer) (i * STEP)).toString();
			int a = fm.stringWidth(s);
			g.drawString(s, x - a / 2, X - MARK);
		}
		// pos représente l'abscisse du sommet de la flèche
		int pos = (int) (MARGIN 
				+ (this.getWidth() - 2 * MARGIN) 
				/ model.getMaxSpeed() * model.getSpeed());
		int[] x = {pos,
					pos + ARROW_BASE / 2,
					pos + ARROW_THICK / 2,
					pos + ARROW_THICK / 2,
					pos - ARROW_THICK / 2,
					pos - ARROW_THICK / 2,
					pos - ARROW_BASE / 2};
		
		int[] y = {Y,
					Y + ARROW_BASE / 2,
					Y + ARROW_BASE / 2,
					Y + ARROW_HEIGHT + ARROW_BASE / 2,
					Y + ARROW_HEIGHT + ARROW_BASE / 2,
					Y + ARROW_BASE / 2,
					Y + ARROW_BASE / 2};
		
		Polygon p = new Polygon(x, y, 7);
		if (model.isOn()) {
			g.setColor(RED);
		} else {
			g.setColor(GRAYED_RED);
		}
		g.fillPolygon(p);
	}
	
	// OUTILS
	
	private void createView() {
		getModel().addObserver(new Observer() {
            public void update(Observable o, Object arg) {
            	repaint();
            }
    	});
	}
	

}
